package com.liaoyifan.core.thread;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;

@SuppressWarnings("NullableProblems")
@Log4j2
public class CoreExecutor implements ExecutorService {

    @Getter private final PoolConfig config;
    private final ExecutorService delegate;
    private final AtomicReference<Exception> firstError;

    public CoreExecutor(PoolConfig config, ExecutorService delegate) {
        this.config = config;
        this.delegate = delegate;
        this.firstError = config.isShutdown() ? new AtomicReference<>() : null;
    }

    @Override
    public void execute(Runnable command) {
        delegate.execute(
                () -> {
                    if (firstError != null && firstError.get() != null) {
                        return; // 如果已发生错误，跳过执行
                    }
                    try {
                        command.run();
                    } catch (Exception e) {
                        if (firstError != null) {
                            firstError.compareAndSet(null, e);
                            delegate.shutdownNow(); // 中断所有任务
                        }
                        log.error("CoreExecutor execute exception", e);
                        throw e; // 抛出异常以触发 Future.get() 的 ExecutionException
                    }
                });
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        return delegate.submit(
                () -> {
                    if (firstError != null && firstError.get() != null) {
                        return null; // 如果已发生错误，跳过执行
                    }
                    try {
                        return task.call();
                    } catch (Exception e) {
                        if (firstError != null) {
                            firstError.compareAndSet(null, e);
                            delegate.shutdownNow(); // 中断所有任务
                        }
                        log.error("CoreExecutor submit exception", e);
                        throw e;
                    }
                });
    }

    @Override
    public <T> Future<T> submit(Runnable task, T result) {
        return submit(Executors.callable(task, result));
    }

    @Override
    public Future<?> submit(Runnable task) {
        return submit(Executors.callable(task));
    }

    @Override
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
            throws InterruptedException {
        return delegate.invokeAll(tasks);
    }

    @Override
    public <T> List<Future<T>> invokeAll(
            Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
            throws InterruptedException {
        return delegate.invokeAll(tasks, timeout, unit);
    }

    @Override
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
            throws InterruptedException, ExecutionException {
        return delegate.invokeAny(tasks);
    }

    @Override
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException {
        return delegate.invokeAny(tasks, timeout, unit);
    }

    @Override
    public void shutdown() {
        delegate.shutdown();
    }

    @Override
    public List<Runnable> shutdownNow() {
        return delegate.shutdownNow();
    }

    @Override
    public boolean isShutdown() {
        return delegate.isShutdown();
    }

    @Override
    public boolean isTerminated() {
        return delegate.isTerminated();
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        return delegate.awaitTermination(timeout, unit);
    }
}
